/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2023-07-01     18421       the first version
 */
#include "netupdata.h"
#include "dev_4gmodule.h"
#include "ota.h"


static struct rt_messagequeue updataMsgMq;
static struct rt_mutex dataSetMutex;

static rt_uint8_t msg_pool[128];

static msgStruct updatamsg;
static uint16_t packageId=1;       //数据上报消息id
static struct updataAllStruct upAstr={0}; //全览数据
static struct UpEvents upEventstr={0}; //特殊事件
static struct UpCtrlPortsSwitch upSwitchstr[8]={0}; //8路开关状态
static struct UpSensorData upsensordata={0}; //开关状态

static struct UpOtaSta upotaStatus={0}; //ota转台

static struct backCmdStruct cmdRebackdata={0};

void updata_AllStruct_Set(struct updataAllStruct *stu)
{
    rt_mutex_take(&dataSetMutex, RT_WAITING_FOREVER);
    if(stu->OtaVersion!=0 && stu->OtaVersion>upAstr.OtaVersion)
    {
        upAstr.OtaVersion=stu->OtaVersion;
    }
    else {
        upAstr.OtaVersion=get_Version();
    }

//    if (rt_strlen(upAstr.ICCID) != 20)
//    {
//        air724ug_get_iccid(upAstr.ICCID);
//    }

    upAstr.BizType=stu->BizType;
    upAstr.Electric=stu->Electric;
    rt_memcpy(upAstr.ForceSta, stu->ForceSta, sizeof(upAstr.ForceSta));
    rt_memcpy(upAstr.SwSta, stu->SwSta, sizeof(upAstr.SwSta));
    rt_mutex_release(&dataSetMutex);
}

void updata_EventStruct_Set(struct UpEvents *stu)
{
//    rt_mutex_take(&dataSetMutex, RT_WAITING_FOREVER); //定时器里中断无法使用rt_mutex_take
    rt_memcpy(&upEventstr, stu, sizeof(struct UpEvents));
//    rt_mutex_release(&dataSetMutex);
    updata_urgent_Notify(1, upEventstr.BizType);

}
void updata_SwStaStruct_Set(struct UpCtrlPortsSwitch *stu)
{
    if(stu->CtrlPort>8 || stu->CtrlPort<1) return;
    rt_mutex_take(&dataSetMutex, RT_WAITING_FOREVER);

    rt_memcpy(&upSwitchstr[stu->CtrlPort-1], stu, sizeof(struct UpCtrlPortsSwitch));
    rt_mutex_release(&dataSetMutex);
    updataNotify(2, stu->CtrlPort);

}

/**
 *
 * @param result 0成功   1不需要执行
 * @param id  平台数据id
 */
void updata_cmdReback(uint8_t result,const char* id ,uint8_t reason)
{
//    {
//    "id": "123",
//    "code": 200,
//    "data": {}
//    }

    rt_mutex_take(&dataSetMutex, RT_WAITING_FOREVER);

    if(result==0)
    {
        cmdRebackdata.code=200;
//        cmdRebackdata.type=0;
    }
    else
    {
        cmdRebackdata.code=304;
//        cmdRebackdata.type=1;
    }

    rt_memcpy(cmdRebackdata.id, id, rt_strlen(id));
    rt_mutex_release(&dataSetMutex);
    updataNotify(5,reason);
}

void updata_SensorStruct_Set(struct UpSensorData *stu)
{
    rt_mutex_take(&dataSetMutex, RT_WAITING_FOREVER);
    rt_memcpy(&upsensordata, stu, sizeof(struct UpSensorData));
    rt_mutex_release(&dataSetMutex);
    updataNotify(4,upsensordata.BizType);
}

/**
 *
 * @param status 1等待升级 2升级中  3升级完成  -1升级失败
 */
void updata_otaStaStruct_Set(int status)
{
    rt_mutex_take(&dataSetMutex, RT_WAITING_FOREVER);
    upotaStatus.status=status;
    rt_mutex_release(&dataSetMutex);
    updataNotify(3,2);
}



/**
 *
 * @param type   0 全览数据
 *               1 特殊事件
 *               2 线路开关状态变更
 *               3 ota状态反馈
 *               4 485传感器设备
 *               5 指令反馈
 *               6 otaVersion
 * @param reason
 *  (对于0 1 4类型)
 *              0  设备上线触发
                1   按键触发
                2   指令下发触发
                3   阈值或异常触发
                4   定时触发
 *  (对于2类型)
 *              表示开关通道 1-8
     (对于5 )    1按键控制 2ota
     (对于6 )
 *
 * @return
 */

rt_uint8_t updataNotify(uint8_t type, uint8_t reason)
{

    updatamsg.type=type;
    updatamsg.reason=reason;

    rt_mq_send(&updataMsgMq,&updatamsg,sizeof(msgStruct));
    return RT_EOK;
}
//紧急通知
rt_uint8_t updata_urgent_Notify(uint8_t type, uint8_t reason)
{

    updatamsg.type=type;
    updatamsg.reason=reason;

    rt_mq_urgent(&updataMsgMq,&updatamsg,sizeof(msgStruct));
    return RT_EOK;
}
//全览数据上报
rt_uint8_t updataAllData(rt_uint8_t reason)
{

    char topic[128] = { 0 };
    char data_buf[512]={0};
    otaversion_t version;
    rt_mutex_take(&dataSetMutex, RT_WAITING_FOREVER);
    version=otaVersinToStuct(upAstr.OtaVersion);

    rt_sprintf(topic, "%s/%s/%s", EVENT_UP_TOPIC_HEAD,air724ug_get_deviceSercet(), EVENT_UP_ALL_PARAMETERS);
//    {\22id\22:\22123\22,\22data\22:{\22BizType\22:0,\22Signal\22:27,\22OtaVersion\22:\221.0\22,\22Electric\22:1,\22SwitchStates\22:[1,1,1,1,1,1,1,1],\22ForceStates\22:[1,1,1,1,1,1,1,1]}}
//    char data[]="{\\22id\\22:\\22123\\22,\\22data\\22:{\\22BizType\\22:0,\\22Signal\\22:27,\\22OtaVersion\\22:\\221.0\\22,\\22Electric\\22:1,\\22SwitchStates\\22:[1,1,1,1,1,1,1,1],\\22ForceStates\\22:[1,1,1,1,1,1,1,1]}}";

    ari724ug_get_csq(&upAstr.Signal);
    if (rt_strlen(upAstr.ICCID) != 20)
    {
        air724ug_get_iccid(upAstr.ICCID);
    }
    rt_sprintf(data_buf,
                   "{\\22id\\22:\\22%d\\22,\\22data\\22:{\\22BizType\\22:%d,\\22Signal\\22:%d,\\22OtaVersion\\22:\\22%d.%d.%d\\22,\\22Electric\\22:%d,\\22Iccid\\22:\\22%s\\22,\\22SwitchStates\\22:[%d,%d,%d,%d,%d,%d,%d,%d],\\22ForceStates\\22:[%d,%d,%d,%d,%d,%d,%d,%d]}}",
                   packageId,reason, upAstr.Signal,version.ota_MajorVersion,version.ota_ChildVersion,version.ota_ReVision,
                   upAstr.Electric,upAstr.ICCID,
                   upAstr.SwSta[0],upAstr.SwSta[1],upAstr.SwSta[2],upAstr.SwSta[3],upAstr.SwSta[4],upAstr.SwSta[5],upAstr.SwSta[6],upAstr.SwSta[7],
                   upAstr.ForceSta[0],upAstr.ForceSta[1],upAstr.ForceSta[2],upAstr.ForceSta[3],upAstr.ForceSta[4],upAstr.ForceSta[5],upAstr.ForceSta[6],upAstr.ForceSta[7]);

    rt_mutex_release(&dataSetMutex);

    if(RT_EOK!=air724x_mqtt_publish_ack(topic, data_buf, 1))
    {
        return RT_ERROR;
    }
    rt_kprintf("[dataPub]mqtt pub [%s,%s]OK\n",topic,data_buf);
    packageId++;
    return RT_EOK;
}

//特殊事件上报,此处reason不管用，默认为3，异常触发
rt_uint8_t updataEventsData(rt_uint8_t reason)
{
    char topic[128] = { 0 };
    char data[128]={0};
    uint8_t result;
 /*{
     "id":"123",
     "data":
     {"BizType": 3,
     "EventType": 1, // 事件类型，1 异常停电告警
     "CtrlPort" : 0 // 线路编号，如果是智能控制器本身，则此项值填0}
     }
*/
    rt_mutex_take(&dataSetMutex, RT_WAITING_FOREVER);
    rt_sprintf(topic, "%s/%s/%s", EVENT_UP_TOPIC_HEAD,air724ug_get_deviceSercet(), EVENT_UP_EVENT_PARAMETERS);

    rt_sprintf(data, "{\\22id\\22:\\22%d\\22,\\22data\\22:{\\22BizType\\22:3,\\22EventType\\22:%d,\\22CtrlPort\\22:0}}",
            packageId,upEventstr.EventType);
    rt_mutex_release(&dataSetMutex);
    result=air724x_mqtt_publish_ack(topic, data, 1);

    if(1==upEventstr.EventType)
    {
        //如果断电告警，断开mqtt
        air724x_mqtt_disconnect();
    }
    if (RT_EOK != result)
    {
        rt_kprintf("[dataPub]mqtt pub [%s,%s]ERROR\n",topic,data);

        return RT_ERROR;
    }
    packageId++;
    rt_kprintf("[dataPub]mqtt pub [%s,%s]OK\n",topic,data);


    return RT_EOK;
}

//线路开关状态变更  reason 代表 1-8
rt_uint8_t updataSwitchStatus(rt_uint8_t reason)
{
    char topic[128] = { 0 };
    char data[256]={0};
    /*
     {
     "id":"123",
     "data": {
     "BizType": 1, // 1按键触发、2指令下发触发
     "HandleType": 1, // 当为按键触发时传此项，触发类型：1按键开关、2模式切换
     "CtrlPort": 1, // 线路编号是从1~8，0作为全部
     "SwitchState": 1, //  // 开关状态：0关；1开
     "ForceState": 1 // 分三个档位：1强制开、0强制关、2可遥控
     }
     }
     */
    if (reason > 8 || reason < 1)
    {
        rt_kprintf("[dataPub]Switch NUM error\r\n");
        return 1;
    }
    rt_mutex_take(&dataSetMutex, RT_WAITING_FOREVER);
    rt_sprintf(topic, "%s/%s/%s", EVENT_UP_TOPIC_HEAD,air724ug_get_deviceSercet(), EVENT_UP_SWITCH_PARAMETERS);

    rt_sprintf(data,"{\\22id\\22:\\22%d\\22,\\22data\\22:{\\22BizType\\22:%d,\\22HandleType\\22:%d,\\22CtrlPort\\22:%d,\\22SwitchState\\22:%d,\\22ForceState\\22:%d}}",
            packageId,upSwitchstr[reason-1].BizType,upSwitchstr[reason-1].HandleType,upSwitchstr[reason-1].CtrlPort,upSwitchstr[reason-1].SwitchState,upSwitchstr[reason-1].ForceState);
    rt_mutex_release(&dataSetMutex);

    if (RT_EOK != air724x_mqtt_publish_ack(topic, data, 1))
    {

        return RT_ERROR;
    }
    packageId++;
    rt_kprintf("[dataPub]mqtt pub [%s,%s]OK\n",topic,data);

    return RT_EOK;
}

//传感器数据
rt_uint8_t updataSensorData(rt_uint8_t reason)
{
    char topic[128] = { 0 };
    char data[256]={};
    /*
     {
     "id":"123",
     "data": {
     "BizType": 1, //
     "temperature": %f, // 当为按键触发时传此项，触发类型：1按键开关、2模式切换
     "oxygen_ratio": %f, // 线路编号是从1~8，0作为全部
     "oxygen_value": %f, //  // 开关状态：0关；1开
     }
     }
     */
    rt_sprintf(topic, "%s/%s/%s", EVENT_UP_TOPIC_HEAD,air724ug_get_deviceSercet(), EVENT_UP_SENSOR_PARAMETERS);

    rt_mutex_take(&dataSetMutex, RT_WAITING_FOREVER);

    sprintf(data,
            "{\\22id\\22:\\22%d\\22,\\22data\\22:{\\22BizType\\22:%d,\\22temperature\\22:%.2f,\\22oxygen_ratio\\22:%.2f,\\22oxygen_value\\22:%.2f}}",
            packageId, reason, upsensordata.temperature, upsensordata.oxygen_ratio, upsensordata.oxygen_value);
    rt_mutex_release(&dataSetMutex);
    if (RT_EOK != air724x_mqtt_publish_ack(topic, data, 1))
    {
        return RT_ERROR;
    }
    packageId++;
    rt_kprintf("[dataPub]mqtt pub [%s,%s]OK\n",topic,data);

    return RT_EOK;
}
/**
 *
 * @param reason 1开关命令 2ota命令
 * @return
 */
rt_uint8_t updataCmdRebakcData(rt_uint8_t reason)
{
    char topic[128] = { 0 };
    char data[256]={};
    rt_mutex_take(&dataSetMutex, RT_WAITING_FOREVER);

    if (reason == 1)
    {
        rt_sprintf(topic, "%s/%s/%s/%s", CMD_DOWN_TOPIC_HEAD, air724ug_get_deviceSercet(), CMD_DOWN_CTRL_PARAMETERS,
                CMD_UP_FEEDBACK_TAIL);

        rt_sprintf(data, "{\\22id\\22:\\22%s\\22,\\22code\\22:\\22%d\\22,\\22data\\22:{}}", cmdRebackdata.id,
                cmdRebackdata.code);
    }
    else if(reason==2) //ota
    {
        rt_sprintf(topic, "%s/%s/%s/%s", OTA_DOWN_TOPIC_HEAD, air724ug_get_deviceSercet(), OTA_DOWN_TOPIC_PARAMETERS,
                       CMD_UP_FEEDBACK_TAIL);

               rt_sprintf(data, "{\\22id\\22:\\22%s\\22,\\22code\\22:\\22%d\\22,\\22data\\22:{}}", cmdRebackdata.id,
                       cmdRebackdata.code);
    }
    rt_mutex_release(&dataSetMutex);
    if (RT_EOK != air724x_mqtt_publish_ack(topic, data, 1))
    {
        return RT_ERROR;
    }
    rt_kprintf("[dataPub]mqtt pub [%s,%s]OK\n",topic,data);

    return RT_EOK;
}
/**
 *
 * @param status 状态码
 * @return
 */
rt_uint8_t updataOtaStatus(rt_uint8_t status)
{
    char topic[128] = { 0 };
    char data[128] = { 0 };
    rt_mutex_take(&dataSetMutex, RT_WAITING_FOREVER);

    rt_sprintf(topic, "%s/%s/%s", EVENT_UP_TOPIC_HEAD, air724ug_get_deviceSercet(), EVENT_UP_OTASTA_PARAMETERS);

    rt_sprintf(data, "{\\22id\\22:\\22%d\\22,\\22data\\22:{\\22status\\22:%d}}", packageId, upotaStatus.status);
    rt_mutex_release(&dataSetMutex);
    if (RT_EOK != air724x_mqtt_publish_ack(topic, data, 1))
    {
        return RT_ERROR;
    }
    rt_kprintf("[dataPub]mqtt pub [%s,%s]OK\n", topic, data);
    packageId++;

    return RT_EOK;
}
/**
 *
 * @param status
 * @return
 */
rt_uint8_t updataOtaVersion(rt_uint8_t status)
{
    char topic[128] = { 0 };
    char data[128] = { 0 };
    otaversion_t version;

    rt_mutex_take(&dataSetMutex, RT_WAITING_FOREVER);

    rt_sprintf(topic, "%s/%s/%s", EVENT_UP_TOPIC_HEAD, air724ug_get_deviceSercet(), EVENT_UP_OTAVER_PARAMETERS);

    version=otaVersinToStuct(get_Version());
    rt_sprintf(data, "{\\22id\\22:\\22%d\\22,\\22nodeId\\22:\\22\\22,\\22data\\22:{\\22version\\22:\\22%d.%d.%d\\22}}", packageId,
            version.ota_MajorVersion,version.ota_ChildVersion,version.ota_ReVision);
    rt_mutex_release(&dataSetMutex);
    if (RT_EOK != air724x_mqtt_publish_ack(topic, data, 1))
    {
        return RT_ERROR;
    }
    rt_kprintf("[dataPub]mqtt pub [%s,%s]OK\n", topic, data);
    packageId++;

    return RT_EOK;
}
rt_uint8_t netupdataEntry(void)
{
    rt_uint8_t result = 0;
    msgStruct newUpdata;
    while (1)
    {
        if(rt_mq_recv(&updataMsgMq,&newUpdata, sizeof(msgStruct), RT_WAITING_FOREVER)==RT_EOK)
        {
            switch (newUpdata.type)
            {
            case 0:
                result=updataAllData(newUpdata.reason);
                break;
            case 1:
                result=updataEventsData(newUpdata.reason);
                break;
            case 2:
                result=updataSwitchStatus(newUpdata.reason);
                break;
            case 3:
                result=updataOtaStatus(newUpdata.reason);
                break;
            case 4:
                result=updataSensorData(newUpdata.reason);
                break;
            case 5:
                result = updataCmdRebakcData(newUpdata.reason);
                break;
            case 6:
                result = updataOtaVersion(0);
            default:
                break;
            }

        }
        if(result!=RT_EOK)
        {
            rt_mq_urgent(&updataMsgMq,&newUpdata,sizeof(msgStruct));
            return result;
        }
    }

}


int updataInit()
{
    rt_err_t result;
    result = rt_mutex_init(&dataSetMutex, "datamutex", RT_IPC_FLAG_FIFO);
    if (result != RT_EOK)
    {
        rt_kprintf("init datamutex mutex failed.\n");
        return -1;
    }
        /* 初始化一个 mailbox */
    result = rt_mq_init(&updataMsgMq,
                            "mqt",
                            &msg_pool[0],               /* 内存池指向msg_pool */
                            sizeof(msgStruct),                          /* 每个消息的大小是 1 字节 */
                            sizeof(msg_pool),           /* 内存池的大小是msg_pool的大小 */
                            RT_IPC_FLAG_FIFO);          /* 如果有多个线程等待，按照先来先得到的方法分配消息 */

    if (result != RT_EOK)
      {
          rt_kprintf("init updataMsgmq failed.\n");
          return -1;
      }
//    updataNotify(0,1);
    return result;
}
INIT_COMPONENT_EXPORT(updataInit);
